package cn.anlucky.admin.generation.config;


import cn.anlucky.admin.common.parent.BaseController;
import cn.anlucky.admin.generation.povo.GenTableField;
import cn.anlucky.admin.generation.povo.GenerationPo;
import cn.anlucky.admin.generation.utils.GenUtils;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.fill.Column;
import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;
import com.baomidou.mybatisplus.generator.model.ClassAnnotationAttributes;
import org.apache.commons.lang3.StringUtils;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;


public class GenerationConfig {


    /**
     * 数据库连接信息
     */
    private String dbUrl;
    /**
     * 数据库用户名
     */
    private String dbUserName;
    /**
     * 数据库密码
     */
    private String dbPassword;
    /**
     * 生成配置
     */
    private GenerationPo generationPo;

    /**
     * 构造方法
     * @param generationPo 生成配置
     */
    public GenerationConfig(GenerationPo generationPo) {
        this.dbUrl = generationPo.getDbUrl();
        this.dbUserName = generationPo.getDbUserName();
        this.dbPassword = generationPo.getDbPassword();
        this.generationPo = generationPo;
    }




    /**
     * 获取配置构建器
     *
     * @param tableNames        数据库表名称
     * @param parentPackageName 父包名
     * @param mouldName         模块名
     * @return ConfigBuilder
     */
    public ConfigBuilder getConfigBuilder(List<String> tableNames, String parentPackageName, String mouldName) {
        generationPo.setTableNames(tableNames);
        generationPo.setParentPackage(parentPackageName);
        generationPo.setModuleName(mouldName);
        return new ConfigBuilder(
                this.getPackageConfigBuilder(parentPackageName, mouldName).build(),
                this.getDataSourceConfigBuilder(),
                this.getStrategyConfigBuilder(tableNames),
                null,
                this.getGlobalConfigBuilder(),
                this.getInjectionConfigBuilder(tableNames).build());
    }

    /**
     * 获取数据源配置构建器
     *
     * @return DataSourceConfig
     */
    private DataSourceConfig getDataSourceConfigBuilder() {
        return new DataSourceConfig.Builder(dbUrl, dbUserName, dbPassword)
                .schema("mybatis-plus") // 数据库 schema(部分数据库适用)
                .keyWordsHandler(new MySqlKeyWordsHandler()).build(); // 数据库关键字处理器
    }

    /**
     * 获取全局配置构建器
     *
     * @return GlobalConfig
     */
    private GlobalConfig getGlobalConfigBuilder() {
        return new GlobalConfig.Builder()
                .disableOpenDir() // 允许自动打开输出目录
                .outputDir(generationPo.getOutputDir()) // 设置输出目录
                .author(generationPo.getAuthor()) // 设置作者名
                .enableSpringdoc() // 开启 Swagger 模式
                .dateType(DateType.TIME_PACK) // 设置时间类型策略
                .commentDate("yyyy-MM-dd HH:mm:ss").build();
    }

    /**
     * 获取包配置构建器
     *
     * @param parentPackageName 父包名
     * @param mouldName         父包模块名
     * @return PackageConfig.Builder
     */
    private PackageConfig.Builder getPackageConfigBuilder(String parentPackageName, String mouldName) {
        return new PackageConfig.Builder()
                .parent(parentPackageName) // 设置父包名
                .moduleName(mouldName) // 设置父包模块名
                .entity(generationPo.getEntityPackage()) // 设置 Entity 包名
                .service(generationPo.getServicePackage()) // 设置 Service 包名
                .serviceImpl(generationPo.getServiceImplPackage()) // 设置 Service Impl 包名
                .mapper(generationPo.getMapperPackage()) // 设置 Mapper 包名
                .xml(generationPo.getMapperXmlPackage()) // 设置 Mapper XML 包名
                .controller(generationPo.getControllerPackage()); // 设置 Controller 包名
    }

    /**
     * 获取注入配置构建器
     *
     * @param tableNames 数据库表名称
     * @return InjectionConfig.Builder
     */
    private InjectionConfig.Builder getInjectionConfigBuilder(List<String> tableNames) {
        return new InjectionConfig.Builder()
                .customFile(generationPo.getOtherTemplates())
                .customMap(generationPo.getOtherTemplateParams())
                .beforeOutputFile((tableInfo, objectMap) -> {
                    // 可以在这里添加自定义逻辑，如修改 objectMap 中的配置
                    // 表格
                    HashMap<String, Object> table = new HashMap<>();
                    // 表格java
                    HashMap<String, Object> java = new HashMap<>();
                    // 项目数据
                    HashMap<String, Object> project = new HashMap<>();
                    // 包名 parent + moduleName
                    project.put("packageName", tableInfo.getPackageConfig().getParent());
                    // 模块名
                    project.put("moduleName",tableInfo.getPackageConfig().getModuleName());
                    // 实体名
                    project.put("entityName",tableInfo.getEntityName());
                    project.put("mapperName",tableInfo.getMapperName());
                    project.put("mapperXmlName",tableInfo.getXmlName());
                    project.put("serviceName",tableInfo.getServiceName());
                    project.put("serviceImplName",tableInfo.getServiceImplName());
                    project.put("controllerName",tableInfo.getControllerName());
                    // 表注释
                    table.put("tableName",tableInfo.getName());
                    table.put("comment",tableInfo.getComment());
                    // 数据库表名称
                    java.put("tableNameSmall", StringUtils.toRootLowerCase(tableInfo.getEntityName()));
                    java.put("tableName",tableInfo.getEntityName());
                    java.put("tableNamePath", tableInfo.getEntityPath());
                    List<GenTableField> genTableFields = new ArrayList<>();
                    tableInfo.getFields().forEach(field -> {
                        GenTableField genTableField = new GenTableField();
                        genTableField.setColumnName(field.getColumnName());
                        genTableField.setColumnComment(field.getComment());
                        genTableField.setJavaColumnName(field.getCapitalName());
                        genTableField.setJavaColumnNamePath(field.getPropertyName());
                        genTableField.setIsTableKey(field.isKeyFlag());
                        genTableField.setIsLogicDeleteField(field.isLogicDeleteField());
                        genTableField.setIsFill(StringUtils.isNotBlank(field.getFill()));
                        genTableField.setFill(StringUtils.isNotBlank(field.getFill())?field.getFill():"");
                        genTableField.setJavaType(field.getPropertyType());
                        genTableField.setTsType(GenUtils.ConvertTsType(field.getPropertyType())); // 传入Java Type set方法中自动转换为Ts类型
                        genTableField.setIsRequired(!field.getMetaInfo().isNullable());
                        String defaultValue = field.getMetaInfo().getDefaultValue();
                        genTableField.setDefaultValue(StringUtils.isNotBlank(defaultValue)?defaultValue:"");
                        genTableField.setColumnMaxLength(field.getMetaInfo().getLength());
                        genTableField.setJdbcType(field.getMetaInfo().getJdbcType());
                        genTableFields.add(genTableField);
                        // 获得主键
                        if(field.isKeyFlag()){
                            table.put("tableKey",field.getColumnName());
                            table.put("tableKeyComment",field.getComment());
                            table.put("tableKeyType",field.getColumnType()); // 全大写
                            java.put("tableKey",field.getCapitalName());
                            java.put("tableKeyPath",field.getPropertyName());
                            java.put("tableKeyType",field.getPropertyType()); // 首字母大写
                            java.put("tableKeyTsType", GenUtils.ConvertTsType(field.getPropertyType()));
                        }
                    });
                    objectMap.put("genTableFields1",genTableFields);
                    objectMap.put("project1",project);
                    objectMap.put("table1",table);
                    objectMap.put("java1",java);
                });
    }

    /**
     * 获取策略配置
     *
     * @param tableNames 数据库表名称
     * @return StrategyConfig
     */
    private StrategyConfig getStrategyConfigBuilder(List<String> tableNames) {
        return new StrategyConfig.Builder()
                .addInclude(tableNames) // 设置要生成的表名
                .enableCapitalMode() // 开启大写命名
                .enableSkipView() // 开启跳过视图
                .disableSqlFilter() // 禁用 SQL 过滤
                .entityBuilder() // 实体策略
                .logicDeleteColumnName(generationPo.getDeleteFlagField()) // 逻辑删除字段名
                .enableFileOverride()
                .enableLombok(new ClassAnnotationAttributes("@Data","lombok.Data"),
                        new ClassAnnotationAttributes("@AllArgsConstructor","lombok.AllArgsConstructor"),
                        new ClassAnnotationAttributes("@NoArgsConstructor","lombok.NoArgsConstructor")
                )
                .enableTableFieldAnnotation()
                .naming(NamingStrategy.underline_to_camel) // 下划线转驼峰
                .columnNaming(NamingStrategy.underline_to_camel) // 下划线转驼峰
                .addTableFills(
                        new Column(generationPo.getCreateTimeField(), FieldFill.INSERT), // 自动填充创建时间
                        new Column(generationPo.getUpdateTimeField(), FieldFill.INSERT_UPDATE), // 自动填充更新时间
                        new Column(generationPo.getCreateByField(), FieldFill.INSERT), // 自动填充创建人
                        new Column(generationPo.getUpdateByField(), FieldFill.INSERT_UPDATE) // 自动填充更新人
                )
                .toString(true)
                .fieldUseJavaDoc(true)
                .formatFileName("%s")
                .javaTemplate(generationPo.getEntityTemplate()) // 实体类模板路径
                // .disable() // 禁用实体类生成
                .serviceBuilder() // service 策略
                .enableFileOverride()
                .superServiceClass(ConstVal.SUPER_SERVICE_CLASS)
                .superServiceImplClass(ConstVal.SUPER_SERVICE_IMPL_CLASS)
                .formatServiceFileName("%sService")
                .formatServiceImplFileName("%sServiceImp")
                .serviceTemplate(generationPo.getServiceTemplate()) // service 模板路径
                .serviceImplTemplate(generationPo.getServiceImplTemplate()) // service impl 模板路径
                // .disableService() // 禁用 Service 层生成
                .mapperBuilder() // mapper 策略
                .enableFileOverride()
                .superClass(ConstVal.SUPER_MAPPER_CLASS)
                .enableBaseResultMap()
                .enableBaseColumnList()
                .formatMapperFileName("%sMapper")
                .formatXmlFileName("%sMapper")
                .mapperTemplate(generationPo.getMapperTemplate()) // mapper 模板路径
                .mapperXmlTemplate(generationPo.getMapperXmlTemplate()) // mapper xml 模板路径
                .controllerBuilder() // controller 策略
                .superClass(BaseController.class) // 设置父类
                .enableFileOverride()
                .enableHyphenStyle()
                .enableRestStyle()
                .formatFileName("%sController")
                .template(generationPo.getControllerTemplate()) // controller 模板路径
                .build();
    }

}
